import 'dart:async';
import 'dart:math';
import 'dart:ui';

import 'package:assets_audio_player/assets_audio_player.dart';
import 'package:firebase_admob/firebase_admob.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:native_device_orientation/native_device_orientation.dart';
import 'package:sprintf/sprintf.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '小学数学口算训练',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

const buttonTextColor = Color(0xFFEFEFEF);
const bgColor = Colors.white;
const splashBgColor = Color(0xfffbf9ec);
const mainButtonBgColor = Color(0xffebe9dc);

const bool USE_LANDSCAPE = false;

class MainButton extends Card {
  MainButton({
    @required Widget child,
    @required VoidCallback onPressed,
    EdgeInsetsGeometry margin = const EdgeInsets.all(2),
    bool showBorder = false})
      : super(color: mainButtonBgColor, borderOnForeground: true, semanticContainer: true,
      margin: margin,
      elevation: 5,
      child: OutlineButton(
          shape: RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(20.0))),
          borderSide: showBorder ? BorderSide(color: Colors.white70, width: 1) : BorderSide.none,
          child: child,
          padding: EdgeInsets.only(left:3, right:3),
          splashColor: Colors.redAccent,
          highlightColor: Colors.redAccent,
          highlightElevation: 15.0,
          onPressed: onPressed)
  );
}

Widget _mainText(String text) {
  return Text(text, style: TextStyle(fontSize: 18),);
}

//加减式子生成函数
typedef List FormulaGenFunc();
const ADD = 0;
const SUB = 1;
const MULT = 2;
const DIV = 3;

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  List addIn10() {
    List ret = [];
    for(int i = 0; i <= 10; i++) {
      for(int j = 0; j <= 10-i; j++) {
        ret.add([ADD, i, j]);
      }
    }
    return ret;
  }

  List subIn10() {
    List ret = [];
    for(int i = 0; i <= 10; i++) {
      for(int j = 0; j <= i; j++) {
        ret.add([SUB, i, j]);
      }
    }
    return ret;
  }

  List addNoCarryIn20() {
    List ret = [];
    for(int i = 10; i < 20; i++) {
      for(int j = 1; j < 20-i; j++) {
        ret.add([ADD, i, j]);
      }
    }
    return ret;
  }

  List addWithCarryIn20() {
    List ret = [];
    for(int i = 2; i < 10; i++) {
      for(int j = 11-i; j < 10; j++) {
        ret.add([ADD, i, j]);
      }
    }
    return ret;
  }

  List subNoAbidicationIn20() {
    List ret = [];
    for(int i = 11; i < 20; i++) {
      for(int j = 1; j <= i-10; j++) {
        ret.add([SUB, i, j]);
      }
      ret.add([SUB, i, 10]);
    }
    return ret;
  }

  List subWithAbidicationIn20() {
    List ret = [];
    for(int i = 11; i < 20; i++) {
      for(int j = i-9; j <= 9; j++) {
        ret.add([SUB, i, j]);
      }
    }
    return ret;
  }

  List addIn100Ten() {
    List ret = [];
    for(int i = 10; i < 100; i+=10) {
      for(int j = 10; j < 100-i; j+=10) {
        ret.add([ADD, i, j]);
      }
    }
    return ret;
  }

  List addIn100() {
    List ret = [];
    for(int i = 10; i < 100; i++) {
      for(int j = 100-i; j < 100; j++) {
        ret.add([ADD, i, j]);
      }
    }
    return ret;
  }

  List subIn100Ten() {
    List ret = [];
    for(int i = 30; i < 100; i+=10) {
      for(int j = 10; j <= i; j+=10) {
        ret.add([SUB, i, j]);
      }
    }
    return ret;
  }

  List subIn100() {
    List ret = [];
    for(int i = 30; i < 100; i++) {
      for(int j = 1; j <= i; j++) {
        ret.add([SUB, i, j]);
      }
    }
    return ret;
  }

  List multi9() {
    List ret = [];
    for(int i = 1; i < 10; i++) {
      for(int j = 1; j < 10; j++) {
        ret.add([MULT, i, j]);
      }
    }
    return ret;
  }

  List div9() {
    List ret = [];
    for(int i = 1; i < 10; i++) {
      for(int j = 1; j < 10; j++) {
        ret.add([DIV, i*j, j]);
      }
    }
    return ret;
  }

  List genExercise() {
    List ret = addIn10();
    ret.addAll(subIn10());
    ret.addAll(addNoCarryIn20());
    ret.addAll(addWithCarryIn20());
    ret.addAll(subNoAbidicationIn20());
    ret.addAll(subWithAbidicationIn20());
    return ret;
  }

  Widget _mainGridView() {
    return NativeDeviceOrientationReader(builder: (context) {
      NativeDeviceOrientation orientation = NativeDeviceOrientationReader.orientation(context);
      bool isLandscape = false;
      if(orientation == NativeDeviceOrientation.landscapeLeft
          || orientation == NativeDeviceOrientation.landscapeRight) {
        isLandscape = true;
      }

      return GridView.count(crossAxisCount: isLandscape ? 5 : 3,
        childAspectRatio: isLandscape ? 1.1 : 1.0,
        padding: const EdgeInsets.all(5.0),
        mainAxisSpacing: 8.0,
        crossAxisSpacing: 8.0,
        children: <Widget>[
          MainButton(child: _mainText('10以内加法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('10以内加法', () {
              return addIn10();
            })));
          },),
          MainButton(child: _mainText('10以内减法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('10以内减法', () {
              return subIn10();
            })));
          },),
          MainButton(child: _mainText('10以内混合'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('10以内混合加减法', () {
              List ret = addIn10();
              ret.addAll(subIn10());
              return ret;
            })));
          },),
          MainButton(child: _mainText('20以内不进位加法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('20以内不进位加法', () {
              return addNoCarryIn20();
            })));
          },),
          MainButton(child: _mainText('20以内进位加法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('20以内进位加法', () {
              return addWithCarryIn20();
            })));
          },),
          MainButton(child: _mainText('20以内不退位减法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('20以内不退位减法', () {
              return subNoAbidicationIn20();
            })));
          },),
          MainButton(child: _mainText('20以内退位减法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('20以内退位减法', () {
              return subWithAbidicationIn20();
            })));
          },),
          MainButton(child: _mainText('20以内混合(不含退位减法)'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('20以内混合加减法(不含退位减法)', () {
              List ret = addIn10();
              ret.addAll(subIn10());
              ret.addAll(addNoCarryIn20());
              ret.addAll(addWithCarryIn20());
              ret.addAll(subNoAbidicationIn20());
              return ret;
            })));
          },),
          MainButton(child: _mainText('20以内混合'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('20以内混合加减法', () {
              List ret = addIn10();
              ret.addAll(subIn10());
              ret.addAll(addNoCarryIn20());
              ret.addAll(addWithCarryIn20());
              ret.addAll(subNoAbidicationIn20());
              ret.addAll(subWithAbidicationIn20());
              return ret;
            })));
          },),
          MainButton(child: _mainText('100以内加法(整10)'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('100以内加法(整10)', () {
              return addIn100Ten();
            })));
          },),
          MainButton(child: _mainText('100以内加法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('100以内加法', () {
              return addIn100();
            })));
          },),
          MainButton(child: _mainText('100以内减法(整10)'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('100以内减法(整10)', () {
              return subIn100Ten();
            })));
          },),
          MainButton(child: _mainText('100以内减法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('100以内减法', () {
              return subIn100();
            })));
          },),
          MainButton(child: _mainText('乘法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('乘法', () {
              return multi9();
            })));
          },),
          MainButton(child: _mainText('除法'), onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => MathExercise('除法', () {
              return div9();
            })));
          },),
          MainButton(child: _mainText('口算题目打印'), onPressed: () {
            List<String> funcs = [
              "10以内加法", "10以内减法", "10以内混合", "20以内不进位加法",
              "20以内进位加法", "20以内不退位减法", "20以内退位减法",
              "20以内混合（不含退位减法）", "20以内混合", "100以内加法", "100以内减法", "乘法", "除法",
            ];
            Map<String, bool> funcsMap = {};
            funcs.forEach((String s) {
              funcsMap[s] = new Random().nextBool();
            });
            showDialog(context: context, builder: (context) {
              return AlertDialog(title: Text('口算题目打印'),
                content: Column(children: funcs.map((s) {
                  return CheckboxListTile(title: Text(s), value: funcsMap[s], onChanged: (bool v) {

                  },);
                }).toList()),
                actions: <Widget>[
                  IconButton(icon:Icon(Icons.print), onPressed: () {

                  },)
                ],
              );
            });
          },),
        ],
      );
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('小学数学口算训练'),
      ),
      body: Container(color: bgColor,
        child: _mainGridView(),
      ),
    );
  }
}

// 口算练习
class MathExercise extends StatefulWidget {
  final String title;
  final FormulaGenFunc formulaGenFunc;

  MathExercise(this.title, this.formulaGenFunc);

  @override
  State<StatefulWidget> createState() {
    return _MathExerciseState();
  }
}

class _MathExerciseState extends State<MathExercise> with WidgetsBindingObserver {
  List _testFormulas = [];
  int _curIdx = -1;
  int _timeValue = 1;
  Timer _timer;
  bool _testing = false;
  DateTime _startDateTime;
  String _resTimeString = '';
  String _centerString = '';

  AssetsAudioPlayer _audioPlayer = AssetsAudioPlayer();

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    setOrientationLandscape();
  }

  @override
  void dispose() {
    revertOrientation();
    super.dispose();
    WidgetsBinding.instance.removeObserver(this);
    _timer?.cancel();
  }

  void setOrientationLandscape() {
    if(USE_LANDSCAPE) {
      SystemChrome.setEnabledSystemUIOverlays([]);
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeRight,
        DeviceOrientation.landscapeLeft,
      ]);
    }
  }

  void revertOrientation() {
    if(USE_LANDSCAPE) {
      SystemChrome.setEnabledSystemUIOverlays(SystemUiOverlay.values);
      SystemChrome.setPreferredOrientations([
        DeviceOrientation.landscapeRight,
        DeviceOrientation.landscapeLeft,
        DeviceOrientation.portraitUp,
        DeviceOrientation.portraitDown,
      ]);
    }
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.inactive) {
      revertOrientation();
    } else if (state == AppLifecycleState.resumed) {
      setOrientationLandscape();
    }
  }

  void _initTestFormulas() {
    List fs = widget.formulaGenFunc();
    Random rand = new Random();
    while(fs.length > 0) {
      int idx = rand.nextInt(fs.length);
      _testFormulas.add(fs[idx]);
      fs.removeAt(idx);
    }
  }

  void _nextFormula() {
    if(_curIdx >= _testFormulas.length-1) {
      _initTestFormulas();  // 到了最后一个，添加新的列表
    }
    _curIdx ++;
    setState(() {});
  }

  void _prevFormula() {
    if(_curIdx > 0) {
      _curIdx --;
      setState(() {});
    }
  }

  String _curFormulaString() {
    if(_testFormulas.length == 0 || _curIdx < 0 || _curIdx >= _testFormulas.length)
      return "";
    List item = _testFormulas[_curIdx];
    switch(item[0]) {
      case ADD:
        return '${item[1]} + ${item[2]}';
      case SUB:
        return '${item[1]} - ${item[2]}';
      case MULT:
        return '${item[1]} * ${item[2]}';
      case DIV:
        return '${item[1]} / ${item[2]}';
      default:
        return '';
    }
    return '${item[1]} ' + (item[0] == ADD ? '+' : '-') + ' ${item[2]}';
  }

  void _startTest() {
    _testing = true;
    _testFormulas = [];   // 清空测试队列
    _initTestFormulas();
    _centerString = '';
    _curIdx = -1;
    _nextFormula();
    _startDateTime = DateTime.now();
    if(_timeValue > 0) {
      _timer = Timer.periodic(Duration(milliseconds: 500), (timer) {
        Duration dur = DateTime.now().difference(_startDateTime);
        if(dur.inSeconds >= _timeValue*60) {
          _stopTest();
          _testEnd();
        } else {
          int sec = _timeValue*60 - dur.inSeconds;
          _resTimeString = sprintf("%02d:%02d", [sec~/60, sec%60]);
        }
        if(mounted)
          setState(() {});
      });
    }
  }

  void _stopTest() {
    if(_timer != null)
      _timer.cancel();
    _testing = false;
    _startDateTime = null;
    _resTimeString = '';
  }

  void _testEnd() {
    _audioPlayer.open(AssetsAudio(
      asset: "waltz.mp3",
      folder: "assets/sound/",
    ));
    _audioPlayer.play();

    String resultTxt;
    if(_timeValue > 0) {
      resultTxt = '本次测试${_timeValue}分钟，完成了${_curIdx}题，速度为：${((_curIdx/_timeValue)+0.5).toInt()}题每分钟';
    } else {
      Duration dur = DateTime.now().difference(_startDateTime);
      int sec = dur.inSeconds;
      resultTxt = '本次测试完成了${_curIdx}题，用时${sprintf("%02d:%02d", [sec~/60, sec%60])}';
    }

    showDialog(context: context, builder: (context) {
      return AlertDialog(title: Text('测试结果'),
        content: Text(resultTxt, maxLines: 5,),
      );
    }).then((value) {
      _audioPlayer.stop();
      setState(() {
        _centerString = resultTxt;
      });
    });
  }

  Widget _textItem(String text) {
    return Text(text, style: TextStyle(fontSize: 18));
  }


  @override
  Widget build(BuildContext context) {
    return USE_LANDSCAPE ? _landscapeWidget(context) : _portraitWidget(context);
  }

  Widget _timeDropdown() {
    return Row(children: <Widget>[
      Text('限时：', style: TextStyle(fontSize: 18),),
      DropdownButton(
        value: _timeValue,
        items: [
          DropdownMenuItem(value: 0, child: _textItem('不限时')),
          DropdownMenuItem(value: 1, child: _textItem('1分钟')),
          DropdownMenuItem(value: 2, child: _textItem('2分钟')),
          DropdownMenuItem(value: 3, child: _textItem('3分钟')),
          DropdownMenuItem(value: 4, child: _textItem('4分钟')),
          DropdownMenuItem(value: 5, child: _textItem('5分钟')),
          DropdownMenuItem(value: 10, child: _textItem('10分钟')),
        ],
        onChanged: (newValue) {
          setState(() {
            _timeValue = newValue;
          });
        },
      ),
    ]);
  }

  Widget _startStopButton() {
    return Card(shape: CircleBorder(), elevation: 5,child:OutlineButton(
      shape: CircleBorder(),
      borderSide: BorderSide(color: Colors.white70, width: 1),
      child: Icon(_testing ? Icons.stop : Icons.play_arrow, size: 60, color: Colors.redAccent,),
      padding: EdgeInsets.only(left:3, right:3),
      splashColor: Colors.greenAccent,
      highlightColor: Colors.greenAccent,
      highlightElevation: 15.0,
      onPressed: () {
        setState(() {
          _testing ? _stopTest() : _startTest();
        });
      },
    ));
  }

  Widget _prevNextButton() {
    return Row(mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[
      Container(margin: EdgeInsets.only(left: 15, right:15, bottom: 10), child:RaisedButton(child: Text("下一题", style: TextStyle(fontSize: 20),),
          onPressed: _testing ? () => _nextFormula() : null
      ),),

      Container(margin: EdgeInsets.only(left: 15, right:15, bottom: 10), child:RaisedButton(child: Text("上一题", style: TextStyle(fontSize: 20),),
          onPressed: _testing && _curIdx > 0 ? () => _prevFormula() : null
      ),),
    ],);
  }

  Widget _landscapeWidget(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
          leading: IconButton(icon:BackButtonIcon(), onPressed: () {
            Navigator.maybePop(context);
            revertOrientation();
            //Future.delayed(Duration(milliseconds: 100), () {
            //  Navigator.maybePop(context);
            //});
          },),
          title: Row(mainAxisAlignment: MainAxisAlignment.spaceAround, children: <Widget>[
            Text(widget.title),
            _timeDropdown(),
          ],)),
      body: Column(children: <Widget>[
        Expanded(flex: 1, child:Padding(padding: EdgeInsets.only(left: 10, right: 20, top: 10, bottom: 5),
          child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[
            Column(mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
              Text(_resTimeString),
              Padding(padding: EdgeInsets.only(top: 15), child: _startStopButton(),),
            ]),

            Expanded(flex: 1, child:Stack(children: <Widget>[
              Card(
                margin: EdgeInsets.all(3),
                elevation: 10,
                child: Center(child: _centerString.isEmpty ? Text(_curFormulaString(), style: TextStyle(fontSize: 140),)
                    : Text(_centerString, style: TextStyle(fontSize: 25)),
                ),
              ),
              _testing ? Positioned(left: 5, top: 1, child: Text('$_curIdx')) : Container(),
            ],),),
          ],),
        ),),
        _prevNextButton(),
      ],),
    );
  }

  Widget _portraitWidget(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title, style: TextStyle(fontSize: 18),),),
      body: Column(children: <Widget>[
        Row(crossAxisAlignment: CrossAxisAlignment.center, children: <Widget>[
              Padding(padding: EdgeInsets.only(top: 10, bottom: 5), child: _startStopButton(),),
              Expanded(flex: 1, child: Text(_resTimeString, style: TextStyle(fontSize: 16), textAlign: TextAlign.left,),),
              Padding(padding: EdgeInsets.only(left: 30, right: 15), child: _timeDropdown()),
        ]),

        Stack(children: <Widget>[
            SizedBox(width: MediaQuery.of(context).size.width,
              height: MediaQuery.of(context).size.width*2/3,
              child: Card(
                margin: EdgeInsets.all(10),
                elevation: 10,
                child: Padding(padding: EdgeInsets.all(8), child: Center(child: _centerString.isEmpty ? Text(_curFormulaString(), style: TextStyle(fontSize: 100),)
                    : Text(_centerString, style: TextStyle(fontSize: 25)),
                ),),
              ),
            ),
            _testing ? Positioned(left: 12, top: 8, child: Text('$_curIdx')) : Container(),
          ],),
        _prevNextButton(),
      ],),
    );
  }
}

// 口算综合测试
class AllTest extends StatefulWidget {
  final String title;
  final FormulaGenFunc formulaGenFunc;

  AllTest(this.title, this.formulaGenFunc);

  @override
  State<StatefulWidget> createState() {
    return _AllTestState();
  }
}

class _AllTestState extends State<AllTest> {

  @override
  void initState() {
    super.initState();

  }

  void _initTestList() {

  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget.title)),
    );
  }
}

